/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package view.contents;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.imageio.ImageIO;
import javax.swing.JFrame;

import model.Content;
import model.Player;
import view.contents.transition.ImageTransition;
import view.contents.transition.TransitionFactory;
import config.Debug;
import controller.ScheduleController;
import controller.UpdateChecker;

/**
 * 
 * @author Yang Wang <yang@digitalmenubox.com>
 */
public class ImageBox extends ContentBox implements ImageTransitioner {

	private int id;
	private String filename = null;
	private int width;
	private int height;
	private Content content;
	private Content transitionContent;
	private BufferedImage image = null;
	private BufferedImage overlayImage = null;
	private BufferedImage transitionImage = null;
	private ImageTransition transition;
	private boolean successfullyInitialized = false;
	private static Map<String, BufferedImage> imageStore = new HashMap<String, BufferedImage>();

	public static void resetBuffer() {
		imageStore = null;
		imageStore = new HashMap<String, BufferedImage>();
	}

	public ImageBox(Content c) {
		content = c;
		this.id = c.getId();
		this.filename = c.getContent();
		this.width = 200;
		this.height = 200;
		this.init();
	}

	public ImageBox(Content c, int width, int height) {
		content = c;
		this.id = c.getId();
		this.filename = c.getContent();
		this.width = width;
		this.height = height;
		this.init();
	}

	public ImageBox(String filename, int width, int height) {
		this.filename = filename;
		this.width = width;
		this.height = height;
		this.init();

	}

	public void init() {
		this.setDoubleBuffered(true);
		this.setOpaque(false);

		this.setLayout(new BorderLayout());
		this.setPreferredSize(new Dimension(this.getWidth(), this.getHeight()));
		if (content.hasUpdate()) {
			// System.out.println("Content has update");
			return;
		}
		// if the image is already loaded, then we don't have to read from file
		// again
		if (imageStore.get(config.Settings.getImageDirectory() + filename) != null) {
			// System.out.println("Image store contains " + filename);
			BufferedImage image = imageStore.get(config.Settings.getImageDirectory() + filename);
			if (image.getWidth() == this.getWidth() && image.getHeight() == this.getHeight()) {
				this.image = image;
				return;
			} else {
				// image with same filename but different size
			}
		}

		int imageW = this.getWidth();
		int imageH = this.getHeight();
		File imageFile = new File(config.Settings.getImageDirectory() + filename);
		if (!imageFile.exists()) {
			Debug.log("File not found: " + imageFile.getPath(), Debug.WARNING_LEVEL);
			ScheduleController.setSkipRecord(true);
			return;
		} else if (!imageFile.canRead()) {
			Debug.log("Image file cannot be read at this moment: " + imageFile.getPath(), Debug.EXCEPTION_LEVEL);
			ScheduleController.setSkipRecord(true);
			return;
		}
		BufferedImage bi = null;
		try {
			bi = ImageIO.read(imageFile);
		} catch (IOException ex) {
			ScheduleController.setSkipRecord(true);
			Debug.log("IOException occured trying to read imageFile " + imageFile.toString(), Debug.ERROR_LEVEL);
			// Logger.getLogger(ImageBox.class.getName()).log(Level.SEVERE, null, ex);
			return;
		} catch (IllegalArgumentException ex) {
			ScheduleController.setSkipRecord(true);
			// Logger.getLogger(ImageBox.class.getName()).log(Level.SEVERE, null, ex);
			Debug.log("IllegalArgumentException occured trying to read imageFile " + imageFile.toString(), Debug.ERROR_LEVEL);
			return;
		} catch(Exception ex) {
			System.out.println(imageFile);
			ScheduleController.setSkipRecord(true);
			Debug.log("Exception occured trying to read imageFile " + imageFile.toString(), Debug.ERROR_LEVEL);
			return;
		}
		if (bi == null) {
			return;
		}
		this.image = new BufferedImage(this.width, this.height, BufferedImage.TYPE_INT_ARGB);
		Graphics g2 = image.getGraphics();
		g2.drawImage(bi, 0, 0, imageW, imageH, null, null);

		// store image in imageStore for later use
		if (!content.hasUpdate()) {
			imageStore.put(config.Settings.getImageDirectory() + filename, image);
		}

		this.setSuccessfullyInitialized(true);

	}

	private void setRedownloadNeeded() {
		// postcondition: update checker will schedule to download the content
		// for this image box next time it runs
		if (this.content == null) {
			return;
		}
		this.content.setHasUpdate(true);
		UpdateChecker.setNeedDownloadContent(true);
	}

	@Override
	public int getHeight() {
		return this.height;
	}

	@Override
	public int getWidth() {
		return this.width;
	}

	public void setFilename(String file) {
		this.filename = file;
	}

	@Override
	protected void paintComponent(Graphics g) {
		// used to stretch the image if it is not the same dimension as the
		// container
		Graphics2D g2d = (Graphics2D) g;
		// g2d.clearRect(0, 0, this.width, this.height);
		if (image == null) {
			return;
		}
		g.drawImage(image, 0, 0, null);

		// draw transition image on top of the content Image to create
		// transition effect
		if (this.overlayImage != null && this.transitionImage != null) {
			// g2d.clearRect(0, 0, this.width, this.height);
			g2d.drawImage(this.transitionImage, 0, 0, null);
			// PlayerCanvas.getInstance().getPageLayoutById(Player.getInstance().getCurrentPlaylistRecord().getPageId());

		}
	}

	@Override
	public BufferedImage getOverlayImage() {
		return overlayImage;
	}

	public void setOverlayImage(BufferedImage overlayImage) {
		this.overlayImage = overlayImage;
	}

	@Override
	public void setTransitionImage(BufferedImage transitionImage) {
		this.transitionImage = transitionImage;
		this.repaint();
	}

	public static void main(String[] args) {
		JFrame frame = new JFrame("test");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setBounds(200, 200, 800, 800);
		// frame.getContentPane().add(new ImageBox(new Content(24841)));
		ImageBox ib = new ImageBox(new Content(34), 800, 800);
		frame.getContentPane().add(ib);
		frame.pack();
		frame.setVisible(true);
		ib.transition(new Content(35));

	}

	@Override
	public String getContent() {
		return this.filename;
	}

	@Override
	public void cleanUp() {
		if (image != null) {
			image.getGraphics().dispose();
			image = null;
		}
		if (transitionImage != null) {
			transitionImage.getGraphics().dispose();
			transitionImage = null;
		}
		if (overlayImage != null) {
			overlayImage.getGraphics().dispose();
			overlayImage = null;
		}
		this.removeAll();
		this.revalidate();
	}

	@Override
	public void reinitialize() {
	}

	@Override
	public void initialize() {
	}

	@Override
	/**
	 * This function enables the paintComponent function to draw an overlay image on top of the original content to achieve the transition animation effect
	 * 
	 */
	public void transition(Content c) {
		// System.out.println("transition is called");
		if (!c.getType().equals(this.content.getType()) || Player.getInstance().isPlayingInventory()) {
			return;
		}
		this.transitionContent = c;
		// setup transition image
		File overlayImageFile = new File(config.Settings.getImageDirectory() + this.transitionContent.getContent());
		if (!overlayImageFile.exists()) {
			Debug.log("File not found: " + overlayImageFile.getPath(), Debug.WARNING_LEVEL);
			return;
		}
		BufferedImage bi = null;
		if (imageStore.get(config.Settings.getImageDirectory() + this.transitionContent.getContent()) != null) {
			// System.out.println("Image store contains " + filename);
			bi = imageStore.get(config.Settings.getImageDirectory() + this.transitionContent.getContent());
		} else {
			try {
				bi = ImageIO.read(overlayImageFile);
			} catch (IOException ex) {
				Logger.getLogger(ImageBox.class.getName()).log(Level.SEVERE, null, ex);
				setRedownloadNeeded();
				Debug.log("failed to read image: " + overlayImageFile.getName() + ", " + ex.getMessage(), Debug.EXCEPTION_LEVEL);
				return;
			} catch(IllegalArgumentException ex) {
				Debug.log("IllegalArgumentException trying to read overlayImage " + overlayImageFile.toString(), Debug.ERROR_LEVEL);
				return;
			} catch(Exception ex) {
				Debug.log("Exception occured trying to read overlayImage " + overlayImageFile.toString(), Debug.ERROR_LEVEL);
				return;
			}
		}
		if (bi == null) {
			return;
		}
		this.overlayImage = null;
		this.overlayImage = new BufferedImage(this.width, this.height, BufferedImage.TYPE_INT_ARGB);
		Graphics overlayGraphics = this.overlayImage.getGraphics();
		overlayGraphics.drawImage(bi, 0, 0, this.getWidth(), this.getHeight(), null, null);

		ImageTransition transition = TransitionFactory.getTransition(Player.getInstance().getCurrentPlaylistRecord().getTransition(), this);
		if (transition != null) {
			// this.setTransition(new RandomTransition());

			this.setTransition(transition);
			this.transition.animate(this, 300);
		}
		// System.out.println("Transition finished");
		bi = null;
		overlayGraphics.dispose();

	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public ImageTransition getTransition() {
		return transition;
	}

	public void setTransition(ImageTransition transition) {
		this.transition = transition;
	}

	@Override
	public boolean isSuccessfullyInitialized() {
		return successfullyInitialized;
	}

	public void setSuccessfullyInitialized(boolean successfullyInitialized) {
		this.successfullyInitialized = successfullyInitialized;
	}

}
